package io.chance.receiverlei.schedule;

import lrq.common.MyLog;
import lrq.common.PropertiesUnit;
import org.apache.log4j.Logger;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.text.ParseException;
import java.text.SimpleDateFormat;


public class LogFileArchive implements Job {

    private static final Logger log = MyLog.getLogger("LogFileArchive");
    private static final String logPath = PropertiesUnit.getValue("logPath") + "/";
    private static final SimpleDateFormat sdfDir = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        archiveLog(logPath);
        zipLog(logPath);
    }

    @SuppressWarnings("SameParameterValue")
    synchronized private static void archiveLog(String resPath) {
        log.info("开始进行日志归档……");
        try {
            File file = new File(resPath);
            String[] paths = file.list();
            for (String path : paths) {
                File temp = new File(resPath + "/" + path);
                if (temp.isDirectory()) continue;
                String dateStr = path.substring(path.lastIndexOf(".") + 1);
                if (!dateStr.equals("") && !dateStr.equals("log") && !dateStr.equals("zip") && isValidDate(dateStr)) {
                    file = new File(resPath + "/" + dateStr);
                    if (!file.exists()) {
                        if (file.mkdir()) log.info("创建归档目录成功：" + dateStr);
                        else log.info("创建归档目录失败：" + dateStr);
                    }
                    file = new File(resPath + "/" + dateStr + "/" + path);
                    if (!file.exists() && file.createNewFile()) {
                        log.info("日志转移：" + file.getName());
                        moveFileWithFileChannels(temp, file);
                    }
                }
            }
        } catch (Exception e) {
            log.error("IO错误", e);
        }
    }

    @SuppressWarnings("SameParameterValue")
    synchronized private static void zipLog(String resPath) {
        log.info("开始进行日志压缩……");
        try {
            File file = new File(resPath);
            String[] paths = file.list();
            for (String path : paths) {
                File temp = new File(resPath + "/" + path);
                if (!temp.isDirectory() || !isValidDate(path)) continue;
                try {
                    sdfDir.parse(path);
                    file = new File(resPath + "/" + path + ".zip");
                    if (file.exists() && !file.renameTo(file)) {
                        log.error(file.getAbsolutePath() + "正在被使用，将在下次计划任务归档");
                        return;
                    }
                    String zipFile = CompressUtil.zip(resPath + "/" + path);
                    if (zipFile != null) {
                        log.info("日志文件压缩成功: " + zipFile);
                        deleteDir(temp);
                    } else {
                        log.info("日志文件压缩失败！");
                    }
                } catch (ParseException e) {
                    log.error("归档文件夹日期格式异常", e);
                }
            }
        } catch (Exception e) {
            log.error("IO错误", e);
        }
    }

    synchronized private static void moveFileWithFileChannels(File source, File dest) {
        boolean moveResult = false;
        try (
                FileInputStream fis = new FileInputStream(source);
                FileOutputStream fos = new FileOutputStream(dest);
                FileChannel inputChannel = fis.getChannel();
                FileChannel outputChannel = fos.getChannel()
        ) {
            outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
            moveResult = true;
        } catch (Exception e) {
            log.error("IO错误", e);
        }
        if (moveResult) {
            if (source.delete()) log.info("日志备份删除成功");
            else log.info("日志备份删除失败");
        }
    }

    private static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (String ch : children) {
                boolean success = deleteDir(new File(dir, ch));
                if (!success) {
                    return false;
                }
            }
        }
        // 目录此时为空，可以删除
        return dir.delete();
    }

    private static boolean isValidDate(String str) {
        boolean convertSuccess = true;
        try {
            // 设置lenient为false. 否则SimpleDateFormat会比较宽松地验证日期，比如2007/02/29会被接受，并转换成2007/03/01
//            sdf.setLenient(false);
            sdfDir.parse(str);
        } catch (ParseException e) {
            // 如果throw java.text.ParseException或者NullPointerException，就说明格式不对
            convertSuccess = false;
        }
        return convertSuccess;
    }
}
